﻿using System;
using System.Diagnostics;

namespace IBNet.DayTrade
{
   /// <summary>
   /// An immutable Open-High-Low-Close-Volume-OpenTime price bar.
   /// </summary>
   [DebuggerDisplay("Close: {close}, OpenTime: {openTime.ToLongTimeString()}")]
   public class PriceBar
   {
      private readonly decimal open;
      private readonly decimal high;
      private readonly decimal low;
      private readonly decimal close;
      private readonly long volume;
      private readonly long openTimeSince1970;
      private readonly DateTime openTime;

      /// <summary>
      /// Creates a new PriceBar.
      /// </summary>
      /// <param name="open">The open price.</param>
      /// <param name="high">The high price.</param>
      /// <param name="low">The low price.</param>
      /// <param name="close">The close price.</param>
      /// <param name="volume">The volume.</param>
      /// <param name="openTimeSince1970">The bar open time in seconds since 1970.</param>
      public PriceBar(decimal open, decimal high, decimal low, decimal close,
         long volume, long openTimeSince1970, DateTime openTime)
      {
         this.open = open;
         this.high = high;
         this.low = low;
         this.close = close;
         this.volume = volume;
         this.openTimeSince1970 = openTimeSince1970;
         this.openTime = openTime;
      }

      /// <summary>
      /// Gets the open price.
      /// </summary>
      public decimal Open { get { return open; } }

      /// <summary>
      /// Gets the high price.
      /// </summary>
      public decimal High { get { return high; } }

      /// <summary>
      /// Gets the low price.
      /// </summary>
      public decimal Low { get { return low; } }

      /// <summary>
      /// Gets the close price.
      /// </summary>
      public decimal Close { get { return close; } }

      /// <summary>
      /// Gets the volume.
      /// </summary>
      public long Volume { get { return volume; } }

      /// <summary>
      /// Gets the open time of the price bar as the number of seconds since 1970.
      /// </summary>
      public long OpenTimeSince1970 { get { return openTimeSince1970; } }

      /// <summary>
      /// Gets the open time of the price bar.
      /// </summary>
      public DateTime OpenTime { get { return openTime; } }

      public override string ToString()
      {
         string representation = openTime.ToLongTimeString() +
            " O: " + open + ", H: " + high + ", L: " + low + ", C: " + close +
            ", V: " + volume;
         return representation;
      }

      /// <summary>
      /// A mutable builder for immutable PriceBar.
      /// </summary>
      public class Builder
      {
         /// <summary>
         /// Gets or sets the open.
         /// </summary>
         public decimal Open { get; set; }

         /// <summary>
         /// Gets or sets the high.
         /// </summary>
         public decimal High { get; set; }

         /// <summary>
         /// Gets or sets the low.
         /// </summary>
         public decimal Low { get; set; }

         /// <summary>
         /// Gets or sets the close.
         /// </summary>
         public decimal Close { get; set; }

         /// <summary>
         /// Gets or sets the volume.
         /// </summary>
         public long Volume { get; set; }

         /// <summary>
         /// Gets or sets the open time as the number of seconds since 1970.
         /// </summary>
         public long LongOpenTime { get; set; }

         /// <summary>
         /// Gets or sets the open time.
         /// </summary>
         public DateTime OpenTime { get; set; }

         /// <summary>
         /// Builds a new PriceBar from this PriceBar.Builder.
         /// </summary>
         /// <returns>The built PriceBar.</returns>
         public PriceBar Build()
         {
            PriceBar builtPriceBar = new PriceBar(this);
            return builtPriceBar;
         }
      }

      /// <summary>
      /// Creates a new PriceBar from a PriceBar.Builder.
      /// </summary>
      /// <param name="orderBuilder">The PriceBar.Builder to create the PriceBar from.</param>
      private PriceBar(Builder orderBuilder)
      {
         this.open = orderBuilder.Open;
         this.high = orderBuilder.High;
         this.low = orderBuilder.Low;
         this.close = orderBuilder.Close;
         this.volume = orderBuilder.Volume;
         this.openTimeSince1970 = orderBuilder.LongOpenTime;
         this.openTime = orderBuilder.OpenTime;
      }
   }
}
